<template>
  <div class="image-preview" v-if="isShow">
    <header class="header">
      <span class="student-name"
        >{{ studentName }} &nbsp;
        <span v-if="questionIndex">第{{ questionIndex }} 题</span> </span
      >{{ nowIndex + 1 }}/{{ imgList.length }}
    </header>
    <div class="img-wrapper">
      <div
        :style="{
          transform: `translate(${translateX}px, ${translateY}px)`
        }"
      >
        <img
          ref="img"
          draggable="false"
          @load="onImgLoad"
          :src="imgList[nowIndex]"
          :style="{
            transform: `rotate(${rotateDeg}deg) scale(${scaleRate})`
          }"
        />
      </div>
    </div>
    <button @click="close" class="btn-icon btn-close"></button>
    <button
      :disabled="!canPrevious"
      @click="goPrevious"
      class="btn-icon btn-previous"
    ></button>
    <button
      :disabled="!canNext"
      @click="goNext"
      class="btn-icon btn-next"
    ></button>
    <footer class="footer">
      <button @click="bigger" class="btn-icon btn-zoom-in"></button>
      <button @click="smaller" class="btn-icon btn-zoom-out"></button>
      <button @click="rotate" class="btn-icon btn-rotate"></button>
    </footer>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue'

const isShow = defineModel('isShow')
const props = defineProps({
  questionIndex: {
    required: false
  },
  studentName: {
    required: false
  },
  currentIndex: {
    default: 0
  },
  imgList: {
    default: []
  },
  currentStudentName: {
    default: ''
  }
})

const close = () => {
  isShow.value = false
}

watch(
  () => props.currentIndex,
  (newVal, oldVal) => {
    if (newVal > oldVal) {
      nowIndex.value = 0
    } else {
      nowIndex.value = props.imgList.length - 1
    }
  }
)

/* 切换 */

const nowIndex = ref(props.currentIndex)
const canPrevious = computed(() => nowIndex.value !== 0)
const canNext = computed(() => nowIndex.value !== props.imgList.length - 1)
function goPrevious() {
  changeImg(nowIndex.value - 1)
}
function goNext() {
  changeImg(nowIndex.value + 1)
}

function changeImg(index) {
  img.value.style.opacity = '0'
  setTimeout(() => {
    img.value.style.transition = 'none'
    reset()
    nowIndex.value = index
  }, 100)
}

function onImgLoad(e) {
  const targetImg = e.target
  const { naturalWidth, naturalHeight } = targetImg
  const { width, height } =
    targetImg.parentElement.parentElement.getBoundingClientRect()
  scaleRate.value = Number(
    Math.min(width / naturalWidth, height / naturalHeight).toFixed(1)
  )
  img.value.style.opacity = '1'
  img.value.style.transition = ''
}

/* 缩放与拖动 */

const scaleRate = ref(1)

function bigger() {
  scaleRate.value = Number((scaleRate.value + 0.2).toFixed(1))
}

function smaller() {
  if (scaleRate.value <= 0.2) {
    scaleRate.value = 0.2
    return
  }
  scaleRate.value = Number((scaleRate.value - 0.2).toFixed(1))
}

const img = ref()
const dragging = ref(false)
const translateX = ref(0)
const translateY = ref(0)
let cding = false
const cd = 5

onMounted(() => {
  img.value.addEventListener('pointerdown', () => {
    dragging.value = true
  })
  img.value?.addEventListener('pointermove', e => {
    if (!dragging.value) {
      return
    }
    if (cding) {
      return
    }
    cding = true
    const { movementX, movementY } = e
    window.requestAnimationFrame(() => {
      translateX.value += movementX
      translateY.value += movementY
    })
    setTimeout(() => {
      cding = false
    }, cd)
  })
  document.addEventListener('pointerup', () => {
    dragging.value = false
  })
  img.value?.addEventListener(
    'wheel',
    e => {
      if (e.deltaY < 0) {
        bigger()
      } else {
        smaller()
      }
    },
    { passive: true }
  )
})

/* 旋转 */

const rotateDeg = ref(0)

function rotate() {
  rotateDeg.value -= 90
}

/* 工具函数 */

function reset() {
  scaleRate.value = 1
  rotateDeg.value = 0
  translateX.value = 0
  translateY.value = 0
}
</script>

<style lang="less" scoped>
.image-preview {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: #f3f5fb;
  z-index: 3000;
}

.btn-icon {
  border: 0;
  width: 86px;
  height: 86px;
  outline: 0;
  border-radius: 30px;
  background-repeat: no-repeat;
  background-position: center;
  cursor: pointer;
  background-color: unset;

  &:disabled {
    opacity: 0.3;
    cursor: not-allowed;
  }
}

.header {
  height: 64px;
  text-align: center;
  line-height: 64px;
  font-size: 20px;
  color: @font-color;

  .student-name {
    margin-right: 16px;
  }
}

.img-wrapper {
  margin: 0 auto;
  width: 1286px;
  height: calc(100% - 64px - 106px);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;

  img {
    transition: all 200ms;
    cursor: move;
  }
}

.btn-close {
  position: absolute;
  top: 24px;
  right: 32px;
  background-image: url('@/assets/images/image-preview/icon-close.png');
}

.btn-previous {
  position: absolute;
  top: 50%;
  left: 32px;
  transform: translateY(-50%);
  background-image: url('@/assets/images/image-preview/icon-arrow-left.png');
}

.btn-next {
  position: absolute;
  top: 50%;
  right: 32px;
  transform: translateY(-50%);
  background-image: url('@/assets/images/image-preview/icon-arrow-right.png');
}

.footer {
  position: relative;
  margin: 0 auto;
  width: 1286px;
  height: 106px;
  display: flex;
  align-items: center;
  justify-content: center;

  .btn-icon {
    margin: 0 16px;
    width: 86px;
    height: 86px;
  }

  .btn-zoom-out {
    background-image: url('@/assets/images/image-preview/icon-zoom-in.png');
    background-size: 47px 47px;
  }

  .btn-zoom-in {
    background-image: url('@/assets/images/image-preview/icon-zoom-out.png');
    background-size: 47px 47px;
  }

  .btn-rotate {
    background-image: url('@/assets/images/image-preview/icon-rotate.png');
    background-size: 47px 47px;
  }

  .btn-secondary {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
  }
}
</style>
